{
  Copyright 2012, Jameel Halabi

  This unit is part of the BlaiseWave wrapper,
  which is licensed under the BSD 2-Clause license (see licenses/license.txt).
}

unit BW_Handler;

{$mode delphi}{$H+}

interface

uses
  BW_CustomObj_Acc,
  BW_Global ,
  BW_Host   ,

  Contnrs   ,

  LW_CustObj,
  LW_Gizmo  ,
  LW_Handler,
  LW_IO     ,
  LW_Render ,
  LW_Server ,
  LW_Tool   ,
  LW_Types  ,
  LW_XPanel ;

type
  THandlerType  = (htWithPanels ,
                   htWithXPanels,
                   htWithGizmo  ) ;
  THandlerTypes = set of THandlerType;

  TDirtyFlag    = (dfWireFrame = LWT_DIRTY_WIREFRAME,
                   dfHelpText  = LWT_DIRTY_HELPTEXT ) ;
  TDirtyFlags   = set of TDirtyFlag;

  TGlobalType   = (gtMessage);
  TGlobalTypes  = set of TGlobalType;

  { THandler }

  THandler = class
  protected
    class var
      FSelf            : TObject         ;
      FGlobalFunc      : TGlobalFunc     ;
      FGlobalList      : TFPHashObjectList;

    var
      FContext         : Pointer         ;
      FEventInfo       : PLWToolEvent    ;
      FCustomObjAccess : TCustomObjAccess;

    function  GetHandlerType                          : String     ; virtual ;
                                                                     abstract;
    function  GetInterfaceType                        : String     ;
    function  GetGizmoType                            : String     ;

    class
    function  Activate
              (      Version    : Integer           ;
                     GlobalFunc : TGlobalFunc       ;
                     Local      : PLWHandler        ;
                     ServerData : Pointer           ) : Integer    ; static  ;

    class
    function  PanelsActivate
              (      Version    : Integer           ;
                     GlobalFunc : TGlobalFunc       ;
                     Local      : PLWInterface      ;
                     ServerData : Pointer           ) : Integer    ; static  ;

    class
    function  XPanelsActivate
              (      Version    : Integer           ;
                     GlobalFunc : TGlobalFunc       ;
                     Local      : PLWInterface      ;
                     ServerData : Pointer           ) : Integer    ; static  ;

    class
    function  GizmoActivate
              (      Version    : Integer           ;
                     GlobalFunc : TGlobalFunc       ;
                     Local      : PLWGizmo          ;
                     ServerData : Pointer           ) : Integer    ; static  ;

    function  ItemActivate
              (      Local      : PLWItemHandler    ) : Integer    ; virtual ;
    function  HandlerActivate
              (      Local      : Pointer           ) : Integer    ; virtual ;
                                                                     abstract;

    function  InstCreate
              (      Context    : Pointer           ;
                     Error      : PPLWError         ) : PLWInstance;
    procedure InstDestroy
              (const Void                           ) ;
    function  InstCopy
              (      From       : PLWInstance       ) : PLWError   ;
    function  InstLoad
              (const LoadState  : PLWLoadState      ) : PLWError   ;
    function  InstSave
              (const SaveState  : PLWSaveState      ) : PLWError   ;
    function  InstDescLn
              (const Void                           ) : PChar      ;

    function  IfcOptions
              (const Void                           ) : PLWError   ;
    function  IfcXPanels
              (const Void                           ) : PLWXPanel  ;
    function  IfcCommand
              (const Command    : PChar             ) : PLWError   ;

    procedure GizmoDraw
              (      DrawAccess : PLWCustomObjAccess) ;
    function  GizmoHelp
              (      EventInfo  : PLWToolEvent      ) : PChar      ;
    function  GizmoDirty
              (const Void                           ) : Integer    ;
    function  GizmoCount
              (      EventInfo  : PLWToolEvent      ) : Integer    ;
    function  GizmoHandle
              (      EventInfo  : PLWToolEvent      ;
               const I          : Integer           ;
                 out Pos        : TLWDVector        ) : Integer    ;
    function  GizmoStart
              (      EventInfo  : PLWToolEvent      ) : Integer    ;
    function  GizmoAdjust
              (      EventInfo  : PLWToolEvent      ;
               const I          : Integer           ) : Integer    ;
    function  GizmoDown
              (      EventInfo  : PLWToolEvent      ) : Integer    ;
    procedure GizmoMove
              (      EventInfo  : PLWToolEvent      ) ;
    procedure GizmoUp
              (      EventInfo  : PLWToolEvent      ) ;

  public
    constructor
              Create
              (Name             : String            ;
               HandlerType      : THandlerTypes
                                = []                ;
               TagInfo          : PServerTagInfo
                                = nil               ) ;              overload;

    function  GetGlobal
              (      Index      : TGlobalType       ) : TObject    ;

    procedure Initialize                              ;              virtual ;
    procedure Finalize                                ;              virtual ;
    procedure Clone                                   ;              virtual ;
    procedure LoadSettings                            ;              virtual ;
    procedure SaveSettings                            ;              virtual ;
    function  SetDescription                          : String     ; virtual ;

    function  BuildXPanels                            : PLWXPanel  ; virtual ;

    procedure Draw                                    ;              virtual ;
    function  Help                                    : String     ; virtual ;
    function  Dirty                                   : TDirtyFlags; virtual ;
    function  Count                                   : Integer    ; virtual ;
    function  Handle
              (const Index      : Integer           ;
                 out Pos        : array of Double   ) : Integer    ; virtual ;
    function  Start                                   : Integer    ; virtual ;
    function  Adjust
              (const Index      : Integer           ) : Integer    ; virtual ;
    function  Down                                    : Boolean    ; virtual ;
    procedure Move                                    ;              virtual ;
    procedure Up                                      ;              virtual ;

    property  Painter   : TCustomObjAccess read  FCustomObjAccess
                                           write FCustomObjAccess;
    property  EventInfo : PLWToolEvent     read  FEventInfo;
  end;

  { TItemHandler }

  TItemHandler = class(THandler)
  protected
    function  ItemActivate
              (      Local  : PLWItemHandler   ) : Integer ; override;
    function  RenderActivate
              (      Local  : PLWRenderHandler ) : Integer ; virtual ;

    function  ItemUseItems
              (const Void                      ) : PPLWItem;
    procedure ItemChangeID
              (const IDList : PPLWItem         ) ;
    procedure ItemChangeName
              (const Data   : PLWNameChangeData) ;

  public
    function  SetRefreshItems                    : PPLWItem; virtual ;
    procedure ChangeID                           ;           virtual ;
    procedure Rename                             ;           virtual ;
  end;

  { TRenderHandler }

  TRenderHandler = class(TItemHandler)
  protected
    function  RenderActivate
              (      Local : PLWRenderHandler) : Integer ; override;

    function  RendInit
              (      Mode  : Integer         ) : PLWError;
    procedure RendCleanup
              (const Void                    ) ;
    function  RendNewTime
              (      Frame : TLWFrame        ;
                     Time  : TLWTime         ) : PLWError;

  public
    procedure PreRender                        ;           virtual ;
    procedure PostRender                       ;           virtual ;
    procedure TimeStep                         ;           virtual ;
  end;

  { TInstUpdate }

  TInstUpdate = class(TGlobal)
  protected
    function  GetGlobalType : String; override;
  end;

  { TXPanel }

  TXPanel = class(TGlobal)
  protected
    function  GetGlobalType : String; override;
  end;

implementation

uses
  SysUtils;

const
  GlobalTypeArray : array [0..0] of TGlobalClass = (TMessage);

{ TXPanel }

function  TXPanel.GetGlobalType : String;
begin
  Result := LWXPANELFUNCS_GLOBAL;
end;

{ TInstUpdate }

function  TInstUpdate.GetGlobalType : String;
begin
  Result := LWINSTUPDATE_GLOBAL;
end;

{ TRenderHandler }

function  TRenderHandler.RenderActivate
                         (      Local : PLWRenderHandler) : Integer ;
begin
  Local.Rend.Init    := Pointer(RendInit   );
  Local.Rend.Cleanup := Pointer(RendCleanup);
  Local.Rend.NewTime := Pointer(RendNewTime);

  Result := HandlerActivate(Local);
end;

function  TRenderHandler.RendInit
                         (      Mode  : Integer         ) : PLWError;
begin
  PreRender;

  Result := nil;
end;

procedure TRenderHandler.RendCleanup
                         (const Void                    ) ;
begin
  PostRender;
end;

function  TRenderHandler.RendNewTime
                         (      Frame : TLWFrame        ;
                                Time  : TLWTime         ) : PLWError;
begin
  TimeStep;

  Result := nil;
end;

procedure TRenderHandler.PreRender                        ;
begin
end;

procedure TRenderHandler.PostRender                       ;
begin
end;

procedure TRenderHandler.TimeStep                         ;
begin
end;

{ TItemHandler }

function  TItemHandler.ItemActivate
                       (      Local  : PLWItemHandler   ) : Integer ;
begin
  Local.Item.UseItems   := Pointer(ItemUseItems  );
  Local.Item.ChangeID   := Pointer(ItemChangeID  );
  Local.Item.ChangeName := Pointer(ItemChangeName);

  Result := RenderActivate(PLWRenderHandler(Local));
end;

function  TItemHandler.RenderActivate
                       (      Local  : PLWRenderHandler ) : Integer ;
begin
  Result := HandlerActivate(Local);
end;

function  TItemHandler.ItemUseItems
                       (const Void                      ) : PPLWItem;
begin
  Result := SetRefreshItems;
end;

procedure TItemHandler.ItemChangeID
                       (const IDList : PPLWItem         ) ;
var
  Index : Integer = 0;
begin
  while IDList[Index] <> nil do
  begin
    if IDList[Index] = FContext then
    begin
      FContext := IDList[Index + 1];
      ChangeID;
      Exit;
    end
    else
      Inc(Index, 2);
  end;

  ChangeID;
end;

procedure TItemHandler.ItemChangeName
                       (const Data   : PLWNameChangeData) ;
begin
  Rename;
end;

function  TItemHandler.SetRefreshItems                    : PPLWItem;
begin
  Result := nil;
end;

procedure TItemHandler.ChangeID                           ;
begin
end;

procedure TItemHandler.Rename                             ;
begin
end;

{ THandler }

function  THandler.GetGlobal
                   (      Index      : TGlobalType       ) : TObject    ;
begin
  Result := FGlobalList.Find(IntToStr(Integer(Index)));
end;

function  THandler.GetInterfaceType                        : String     ;
var
  HandlerType : String;
begin
  HandlerType := GetHandlerType;

  Result := Copy(HandlerType, 1, Pos('Handler', HandlerType) - 1) + 'Interface';
end;

function  THandler.GetGizmoType                            : String     ;
var
  HandlerType : String;
begin
  HandlerType := GetHandlerType;

  Result := Copy(HandlerType, 1, Pos('Handler', HandlerType) - 1) + 'Gizmo';
end;

class
function  THandler.Activate
                   (      Version    : Integer           ;
                          GlobalFunc : TGlobalFunc       ;
                          Local      : PLWHandler        ;
                          ServerData : Pointer           ) : Integer    ;
begin
  with THandler(FSelf) do
  begin
    FGlobalFunc := GlobalFunc;

    FGlobalList := TFPHashObjectList.Create;
    FGlobalList.Add(IntToStr(Integer(gtMessage)), GlobalTypeArray[Integer(gtMessage)].Create(FGlobalFunc, umTransient));

    Local.Inst.Create  := Pointer(InstCreate );
    Local.Inst.Destroy := Pointer(InstDestroy);
    Local.Inst.Copy    := Pointer(InstCopy   );
    Local.Inst.Load    := Pointer(InstLoad   );
    Local.Inst.Save    := Pointer(InstSave   );
    Local.Inst.DescLn  := Pointer(InstDescLn );

    Result := ItemActivate(PLWItemHandler(Local));
  end;
end;

class
function  THandler.PanelsActivate
                   (      Version    : Integer           ;
                          GlobalFunc : TGlobalFunc       ;
                          Local      : PLWInterface      ;
                          ServerData : Pointer           ) : Integer    ;
begin
  if Version <> LWINTERFACE_VERSION then
    Exit(AFUNC_BADVERSION);

  Local.Panel   := nil;
  Local.Options := Pointer(IfcOptions);
  Local.Command := Pointer(IfcCommand);

  Result := AFUNC_OK;
end;

class
function THandler.XPanelsActivate
                  (      Version    : Integer           ;
                         GlobalFunc : TGlobalFunc       ;
                         Local      : PLWInterface      ;
                         ServerData : Pointer           ) : Integer    ;
begin
  if Version <> LWINTERFACE_VERSION then
    Exit(AFUNC_BADVERSION);

  Local.Panel   := Pointer(THandler(FSelf).IfcXPanels(nil^));
  Local.Options := nil;
  Local.Command := Pointer(IfcCommand);

  Result := AFUNC_OK;
end;

class
function  THandler.GizmoActivate
                   (      Version    : Integer           ;
                          GlobalFunc : TGlobalFunc       ;
                          Local      : PLWGizmo          ;
                          ServerData : Pointer           ) : Integer    ;
begin
  Local.Gizmo.Draw   := Pointer(GizmoDraw  );
  Local.Gizmo.Help   := Pointer(GizmoHelp  );
  Local.Gizmo.Dirty  := Pointer(GizmoDirty );
  Local.Gizmo.Count  := Pointer(GizmoCount );
  Local.Gizmo.Handle := Pointer(GizmoHandle);
  Local.Gizmo.Start  := Pointer(GizmoStart );
  Local.Gizmo.Adjust := Pointer(GizmoAdjust);
  Local.Gizmo.Down   := Pointer(GizmoDown  );
  Local.Gizmo.Move   := Pointer(GizmoMove  );
  Local.Gizmo.Up     := Pointer(GizmoUp    );

  Result := AFUNC_OK;
end;

function  THandler.ItemActivate
                   (      Local      : PLWItemHandler    ) : Integer    ;
begin
  Result := HandlerActivate(Local);
end;

function  THandler.InstCreate
                   (      Context    : Pointer           ;
                          Error      : PPLWError         ) : PLWInstance;
begin
  Result := THandler(FSelf).ClassType.Create;
  THandler(Result).FContext := Context;

  THandler(Result).Initialize;
end;

procedure THandler.InstDestroy
                   (const Void                           ) ;
begin
  Finalize;

  Free;
end;

function  THandler.InstCopy
                   (      From       : PLWInstance       ) : PLWError   ;
begin
  Clone;

  Result := nil;
end;

function  THandler.InstLoad
                   (const LoadState  : PLWLoadState      ) : PLWError   ;
begin
  LoadSettings;

  Result := nil;
end;

function  THandler.InstSave
                   (const SaveState  : PLWSaveState      ) : PLWError   ;
begin
  SaveSettings;

  Result := nil;
end;

function  THandler.InstDescLn
                   (const Void                           ) : PChar      ;
begin
  Result := PChar(SetDescription);
end;

function  THandler.IfcOptions
                   (const Void                           ) : PLWError   ;
begin
  Result := nil;
end;

function THandler.IfcXPanels(const Void) : PLWXPanel;
begin
  Result := BuildXPanels;
end;

function  THandler.IfcCommand
                   (const Command    : PChar             ) : PLWError   ;
begin
  Result := nil;
end;

procedure THandler.GizmoDraw
                   (      DrawAccess : PLWCustomObjAccess) ;
begin
  if not Assigned(FCustomObjAccess) then
    FCustomObjAccess := TCustomObjAccess.Create;

  FCustomObjAccess.Access := DrawAccess;

  Draw;
end;

function  THandler.GizmoHelp
                   (      EventInfo  : PLWToolEvent      ) : PChar      ;
begin
  FEventInfo := EventInfo;

  Result := PChar(Help);
end;

function  THandler.GizmoDirty
                   (const Void                           ) : Integer    ;
var
  Index : TDirtyFlag;
  Flags : UInt32 = 0 ;
begin
  for Index in Dirty do
    Flags := Flags or Integer(Index);

  Result := Flags;
end;

function  THandler.GizmoCount
                   (      EventInfo  : PLWToolEvent      ) : Integer    ;
begin
  FEventInfo := EventInfo;

  Result := Count;
end;

function  THandler.GizmoHandle
                   (      EventInfo  : PLWToolEvent      ;
                    const I          : Integer           ;
                      out Pos        : TLWDVector        ) : Integer    ;
begin
  FEventInfo := EventInfo;

  Result := Handle(I, Pos);
end;

function  THandler.GizmoStart
                   (      EventInfo  : PLWToolEvent      ) : Integer    ;
begin
  FEventInfo := EventInfo;

  Result := Start;
end;

function  THandler.GizmoAdjust
                   (      EventInfo  : PLWToolEvent      ;
                    const I          : Integer           ) : Integer    ;
begin
  FEventInfo := EventInfo;

  Result := Adjust(I);
end;

function  THandler.GizmoDown
                   (      EventInfo  : PLWToolEvent      ) : Integer    ;
begin
  FEventInfo := EventInfo;

  Result := Integer(Down);
end;

procedure THandler.GizmoMove
                   (      EventInfo  : PLWToolEvent      ) ;
begin
  FEventInfo := EventInfo;

  Move;
end;

procedure THandler.GizmoUp
                   (      EventInfo  : PLWToolEvent      ) ;
begin
  FEventInfo := EventInfo;

  Up;
end;

constructor
          THandler.Create
                   (Name             : String            ;
                    HandlerType      : THandlerTypes     ;
                    TagInfo          : PServerTagInfo    ) ;
begin
  if (htWithPanels  in HandlerType) and
     (htWithXPanels in HandlerType) then
    Exit;

  AddHandler(PChar(Name)            ,
             PChar(GetHandlerType)  ,
             TActivateFunc(Activate), TagInfo);
  FSelf := Self;

  if htWithPanels  in HandlerType then
    AddHandler(PChar(Name)                     ,
               PChar(GetInterfaceType)         ,
               TActivateFunc(PanelsActivate), TagInfo);

  if htWithXPanels in HandlerType then
    AddHandler(PChar(Name)                     ,
               PChar(GetInterfaceType)         ,
               TActivateFunc(XPanelsActivate), TagInfo);

  if htWithGizmo   in HandlerType then
    AddHandler(PChar(Name)                 ,
               PChar(GetGizmoType)         ,
               TActivateFunc(GizmoActivate), TagInfo);
end;

procedure THandler.Initialize                              ;
begin
end;

procedure THandler.Finalize                                ;
begin
end;

procedure THandler.Clone                                   ;
begin
end;

procedure THandler.LoadSettings                            ;
begin
end;

procedure THandler.SaveSettings                            ;
begin
end;

function  THandler.SetDescription                          : String     ;
begin
  Result := '';
end;

function THandler.BuildXPanels : PLWXPanel;
begin
  Result := nil;
end;

procedure THandler.Draw                                    ;
begin
end;

function  THandler.Help                                    : String     ;
begin
  Result := '';
end;

function  THandler.Dirty                                   : TDirtyFlags;
begin
  Result := [];
end;

function  THandler.Count                                   : Integer    ;
begin
  Result := 1;
end;

function  THandler.Handle
                   (const Index      : Integer           ;
                      out Pos        : array of Double   ) : Integer    ;
begin
  Pos[0] := 0;
  Pos[1] := 0;
  Pos[2] := 0;

  Result := 0;
end;

function  THandler.Start                                   : Integer    ;
begin
  Result := 0;
end;

function  THandler.Adjust
                   (const Index      : Integer           ) : Integer    ;
begin
  Result := 0;
end;

function  THandler.Down                                    : Boolean    ;
begin
  Result := False;
end;

procedure THandler.Move                                    ;
begin
end;

procedure THandler.Up                                      ;
begin
end;

end.

